}
}
-pub fn compile(manifest_path: &Path,
- options: &CompileOptions)
- -> CargoResult<ops::Compilation> {
+pub fn compile<'a>(manifest_path: &Path,
+ options: &CompileOptions<'a>)
+ -> CargoResult<ops::Compilation<'a>> {
debug!("compile; manifest-path={}", manifest_path.display());
let mut source = try!(PathSource::for_path(manifest_path.parent().unwrap(),
compile_pkg(&package, options)
}
-pub fn compile_pkg(package: &Package, options: &CompileOptions)
- -> CargoResult<ops::Compilation> {
+pub fn compile_pkg<'a>(package: &Package,
+ options: &CompileOptions<'a>)
+ -> CargoResult<ops::Compilation<'a>> {
let CompileOptions { config, jobs, target, spec, features,
no_default_features, release, mode,
ref filter, ref exec_engine,
profile.rustc_args = Some(args.to_vec());
Some((target, profile))
}
- Some(_) =>
- return Err(human("extra arguments to `rustc` can only be passed to one target, \
- consider filtering\nthe package by passing e.g. `--lib` or \
- `--bin NAME` to specify a single target")),
+ Some(_) => {
+ return Err(human("extra arguments to `rustc` can only be passed to \
+ one target, consider filtering\nthe package by \
+ passing e.g. `--lib` or `--bin NAME` to specify \
+ a single target"))
+ }
None => None,
};
try!(ops::compile_targets(&targets, to_build,
&PackageSet::new(&packages),
- &resolve_with_overrides, &sources,
+ &resolve_with_overrides,
+ &sources,
config,
build_config,
to_build.manifest().profiles()))
use semver::Version;
use core::{PackageId, Package, Target};
-use util::{self, CargoResult};
+use util::{self, CargoResult, Config};
use super::{CommandType, CommandPrototype};
/// A structure returning the result of a compilation.
-pub struct Compilation {
+pub struct Compilation<'cfg> {
/// All libraries which were built for a package.
///
/// This is currently used for passing --extern flags to rustdoc tests later
/// Features enabled during this compilation.
pub features: HashSet<String>,
+
+ config: &'cfg Config,
}
-impl Compilation {
- pub fn new(pkg: &Package) -> Compilation {
+impl<'cfg> Compilation<'cfg> {
+ pub fn new(pkg: &Package, config: &'cfg Config) -> Compilation<'cfg> {
Compilation {
libraries: HashMap::new(),
native_dirs: HashMap::new(), // TODO: deprecated, remove
extra_env: HashMap::new(),
package: pkg.clone(),
features: HashSet::new(),
+ config: config,
}
}
search_path.push(self.deps_output.clone());
let search_path = try!(util::join_paths(&search_path,
util::dylib_path_envvar()));
- let mut cmd = try!(CommandPrototype::new(cmd));
+ let mut cmd = try!(CommandPrototype::new(cmd, self.config));
cmd.env(util::dylib_path_envvar(), &search_path);
for (k, v) in self.extra_env.iter() {
cmd.env(k, v);
PluginAndTarget,
}
-pub struct Context<'a> {
- pub config: &'a Config,
+pub struct Context<'a, 'cfg: 'a> {
+ pub config: &'cfg Config,
pub resolve: &'a Resolve,
- pub sources: &'a SourceMap<'a>,
- pub compilation: Compilation,
+ pub sources: &'a SourceMap<'cfg>,
+ pub compilation: Compilation<'cfg>,
pub build_state: Arc<BuildState>,
pub exec_engine: Arc<Box<ExecEngine>>,
pub fingerprints: HashMap<(&'a PackageId, &'a Target, &'a Profile, Kind),
profiles: &'a Profiles,
}
-impl<'a> Context<'a> {
+impl<'a, 'cfg> Context<'a, 'cfg> {
pub fn new(resolve: &'a Resolve,
- sources: &'a SourceMap<'a>,
+ sources: &'a SourceMap<'cfg>,
deps: &'a PackageSet,
- config: &'a Config,
+ config: &'cfg Config,
host: Layout,
target_layout: Option<Layout>,
root_pkg: &Package,
build_config: BuildConfig,
- profiles: &'a Profiles) -> CargoResult<Context<'a>> {
+ profiles: &'a Profiles) -> CargoResult<Context<'a, 'cfg>> {
let target = build_config.requested_target.clone();
let target = target.as_ref().map(|s| &s[..]);
- let (target_dylib, target_exe) = try!(Context::filename_parts(target));
+ let (target_dylib, target_exe) = try!(Context::filename_parts(target,
+ config));
let (host_dylib, host_exe) = if build_config.requested_target.is_none() {
(target_dylib.clone(), target_exe.clone())
} else {
- try!(Context::filename_parts(None))
+ try!(Context::filename_parts(None, config))
};
let target_triple = target.unwrap_or(config.rustc_host()).to_string();
let engine = build_config.exec_engine.as_ref().cloned().unwrap_or({
host_dylib: host_dylib,
host_exe: host_exe,
requirements: HashMap::new(),
- compilation: Compilation::new(root_pkg),
+ compilation: Compilation::new(root_pkg, config),
build_state: Arc::new(BuildState::new(&build_config, deps)),
build_config: build_config,
exec_engine: engine,
/// Run `rustc` to discover the dylib prefix/suffix for the target
/// specified as well as the exe suffix
- fn filename_parts(target: Option<&str>)
+ fn filename_parts(target: Option<&str>, cfg: &Config)
-> CargoResult<(Option<(String, String)>, String)> {
- let mut process = try!(util::process(util::rustc()));
+ let mut process = try!(util::process(cfg.rustc()));
process.arg("-")
.arg("--crate-name").arg("_")
.arg("--crate-type").arg("dylib")
use std::path::Path;
use std::process::Output;
-use util::{self, CargoResult, ProcessError, ProcessBuilder, process};
+use util::{CargoResult, ProcessError, ProcessBuilder, process};
+use util::Config;
/// Trait for objects that can execute commands.
pub trait ExecEngine: Send + Sync {
}
impl CommandPrototype {
- pub fn new(ty: CommandType) -> CargoResult<CommandPrototype> {
+ pub fn new(ty: CommandType, config: &Config)
+ -> CargoResult<CommandPrototype> {
Ok(CommandPrototype {
builder: try!(match ty {
- CommandType::Rustc => process(util::rustc()),
- CommandType::Rustdoc => process(util::rustdoc()),
+ CommandType::Rustc => process(config.rustc()),
+ CommandType::Rustdoc => process(config.rustdoc()),
CommandType::Target(ref s) |
CommandType::Host(ref s) => process(s),
}),
/// This function will calculate the fingerprint for a target and prepare the
/// work necessary to either write the fingerprint or copy over all fresh files
/// from the old directories to their new locations.
-pub fn prepare_target<'a>(cx: &mut Context<'a>,
- pkg: &'a Package,
- target: &'a Target,
- profile: &'a Profile,
- kind: Kind) -> CargoResult<Preparation> {
+pub fn prepare_target<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,
+ pkg: &'a Package,
+ target: &'a Target,
+ profile: &'a Profile,
+ kind: Kind) -> CargoResult<Preparation> {
let _p = profile::start(format!("fingerprint: {} / {}",
pkg.package_id(), target.name()));
let new = dir(cx, pkg, kind);
///
/// Information like file modification time is only calculated for path
/// dependencies and is calculated in `calculate_target_fresh`.
-fn calculate<'a>(cx: &mut Context<'a>,
- pkg: &'a Package,
- target: &'a Target,
- profile: &'a Profile,
- kind: Kind)
- -> CargoResult<Fingerprint> {
+fn calculate<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,
+ pkg: &'a Package,
+ target: &'a Target,
+ profile: &'a Profile,
+ kind: Kind)
+ -> CargoResult<Fingerprint> {
let key = (pkg.package_id(), target, profile, kind);
match cx.fingerprints.get(&key) {
Some(s) => return Ok(s.clone()),
use std::ffi::OsString;
use std::fs;
use std::io::prelude::*;
-use std::path::{self, PathBuf};
+use std::path::{self, Path, PathBuf};
use std::sync::Arc;
use core::{SourceMap, Package, PackageId, PackageSet, Target, Resolve};
///
/// The second element of the tuple returned is the target triple that rustc
/// is a host for.
-pub fn rustc_version() -> CargoResult<(String, String)> {
- let output = try!(try!(util::process(util::rustc()))
+pub fn rustc_version<P: AsRef<Path>>(rustc: P) -> CargoResult<(String, String)> {
+ let output = try!(try!(util::process(rustc.as_ref()))
.arg("-vV")
.exec_with_output());
let output = try!(String::from_utf8(output.stdout).map_err(|_| {
// Returns a mapping of the root package plus its immediate dependencies to
// where the compiled libraries are all located.
-pub fn compile_targets<'a>(targets: &[(&'a Target, &'a Profile)],
- pkg: &'a Package,
- deps: &PackageSet,
- resolve: &'a Resolve,
- sources: &'a SourceMap<'a>,
- config: &'a Config,
- build_config: BuildConfig,
- profiles: &'a Profiles)
- -> CargoResult<Compilation> {
+pub fn compile_targets<'a, 'cfg: 'a>(targets: &[(&'a Target, &'a Profile)],
+ pkg: &'a Package,
+ deps: &'a PackageSet,
+ resolve: &'a Resolve,
+ sources: &'a SourceMap<'cfg>,
+ config: &'cfg Config,
+ build_config: BuildConfig,
+ profiles: &'a Profiles)
+ -> CargoResult<Compilation<'cfg>> {
if targets.is_empty() {
- return Ok(Compilation::new(pkg))
+ return Ok(Compilation::new(pkg, config))
}
debug!("compile_targets: {}", pkg);
Ok(cx.compilation)
}
-fn compile<'a>(targets: &[(&'a Target, &'a Profile)],
- pkg: &'a Package,
- cx: &mut Context<'a>,
- jobs: &mut JobQueue<'a>) -> CargoResult<()> {
+fn compile<'a, 'cfg>(targets: &[(&'a Target, &'a Profile)],
+ pkg: &'a Package,
+ cx: &mut Context<'a, 'cfg>,
+ jobs: &mut JobQueue<'a>) -> CargoResult<()> {
debug!("compile_pkg; pkg={}", pkg);
let profiling_marker = profile::start(format!("preparing: {}", pkg));
Ok(())
}
-fn prepare_init<'a>(cx: &mut Context<'a>,
- pkg: &'a Package,
- jobs: &mut JobQueue<'a>,
- visited: &mut HashSet<&'a PackageId>) {
+fn prepare_init<'a, 'cfg>(cx: &mut Context<'a, 'cfg>,
+ pkg: &'a Package,
+ jobs: &mut JobQueue<'a>,
+ visited: &mut HashSet<&'a PackageId>) {
if !visited.insert(pkg.package_id()) { return }
// Set up all dependencies
Ok(try!(build_and_run(manifest_path, options, &args)).err())
}
-fn build_and_run(manifest_path: &Path,
- options: &TestOptions,
- test_args: &[String])
- -> CargoResult<Result<Compilation, ProcessError>> {
+fn build_and_run<'a>(manifest_path: &Path,
+ options: &TestOptions<'a>,
+ test_args: &[String])
+ -> CargoResult<Result<Compilation<'a>, ProcessError>> {
let config = options.compile_opts.config;
let mut source = try!(PathSource::for_path(&manifest_path.parent().unwrap(),
config));
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::hash_map::{HashMap};
use std::env;
+use std::ffi::OsString;
use std::fmt;
use std::fs::{self, File};
use std::io::prelude::*;
values: RefCell<HashMap<String, ConfigValue>>,
values_loaded: Cell<bool>,
cwd: PathBuf,
+ rustc: PathBuf,
+ rustdoc: PathBuf,
}
impl Config {
let cwd = try!(env::current_dir().chain_error(|| {
human("couldn't get the current directory of the process")
}));
- let (rustc_version, rustc_host) = try!(ops::rustc_version());
- Ok(Config {
+ let mut cfg = Config {
home_path: try!(homedir().chain_error(|| {
human("Cargo couldn't find your home directory. \
This probably means that $HOME was not set.")
})),
shell: RefCell::new(shell),
- rustc_version: rustc_version,
- rustc_host: rustc_host,
+ rustc_version: String::new(),
+ rustc_host: String::new(),
cwd: cwd,
values: RefCell::new(HashMap::new()),
values_loaded: Cell::new(false),
- })
+ rustc: PathBuf::from("rustc"),
+ rustdoc: PathBuf::from("rustdoc"),
+ };
+
+ cfg.rustc = try!(cfg.get_tool("rustc"));
+ cfg.rustdoc = try!(cfg.get_tool("rustdoc"));
+ let (rustc_version, rustc_host) = try!(ops::rustc_version(cfg.rustc()));
+ cfg.rustc_version = rustc_version;
+ cfg.rustc_host = rustc_host;
+
+ Ok(cfg)
}
pub fn home(&self) -> &Path { &self.home_path }
self.shell.borrow_mut()
}
+ pub fn rustc(&self) -> &Path { &self.rustc }
+
+ pub fn rustdoc(&self) -> &Path { &self.rustdoc }
+
/// Return the output of `rustc -v verbose`
pub fn rustc_version(&self) -> &str { &self.rustc_version }
};
Ok(())
}
+
+ fn get_tool(&self, tool: &str) -> CargoResult<PathBuf> {
+ let var = format!("build.{}", tool);
+ if let Some((tool, path)) = try!(self.get_string(&var)) {
+ if tool.contains("/") || (cfg!(windows) && tool.contains("\\")) {
+ return Ok(path.join(tool))
+ }
+ return Ok(PathBuf::from(tool))
+ }
+
+ let var = tool.chars().flat_map(|c| c.to_uppercase()).collect::<String>();
+ let tool = env::var_os(&var).unwrap_or_else(|| OsString::from(tool));
+ Ok(PathBuf::from(tool))
+ }
}
#[derive(Eq, PartialEq, Clone, RustcEncodable, RustcDecodable, Copy)]
return cargo_home.or(user_home);
}
-pub fn rustc() -> String {
- env::var("RUSTC").unwrap_or_else(|_| "rustc".to_string())
-}
-
-pub fn rustdoc() -> String {
- env::var("RUSTDOC").unwrap_or_else(|_| "rustdoc".to_string())
-}
-
fn walk_tree<F>(pwd: &Path, mut walk: F) -> CargoResult<()>
where F: FnMut(File, &Path) -> CargoResult<()>
{
-pub use self::config::{Config, rustc, rustdoc};
+pub use self::config::Config;
pub use self::process_builder::{process, ProcessBuilder};
pub use self::errors::{CargoResult, CargoError, ChainError, CliResult};
pub use self::errors::{CliError, ProcessError};
timeout = 60000 # Timeout for each HTTP request, in milliseconds
[build]
-jobs = 1 # number of jobs to run by default (default to # cpus)
+jobs = 1 # number of jobs to run by default (default to # cpus)
+rustc = "rustc" # path to the compiler to execute
+rustdoc = "rustdoc" # path to the doc generator to execute
```
# Environment Variables
assert_that(foo.cargo("new")
.arg("-v").arg("foo").cwd(&foo.root().join("foo")),
execs().with_status(101).with_stderr("\
-Failed to create project `foo` at `[..]`
-
-Caused by:
- Couldn't load Cargo configuration
+Couldn't load Cargo configuration
Caused by:
failed to merge key `foo` between files:
assert_that(foo.cargo_process("build").arg("-v"),
execs().with_status(101).with_stderr("\
-failed to parse manifest at `[..]Cargo.toml`
-
-Caused by:
- Couldn't load Cargo configuration
+Couldn't load Cargo configuration
Caused by:
could not parse TOML configuration in `[..]config`
use hamcrest::{assert_that, existing_file, is_not};
use support::paths::CargoPathExt;
use cargo::util::process;
-use cargo::ops::rustc_version;
fn setup() {
}
});
test!(cargo_platform_specific_dependency {
- let (_, host) = rustc_version().unwrap();
+ let host = ::rustc_host();
let p = project("foo")
.file("Cargo.toml", &format!(r#"
[project]
Could not execute process `rustc-that-does-not-exist -vV` ([..])
Caused by:
-[..]
-"));
+[..]".to_string() + if cfg!(windows) {"\n[..]\n"} else {"\n"}));
assert_that(&p.bin("a"), is_not(existing_file()));
});
});
test!(overrides_and_links {
- let (_, target) = ::cargo::ops::rustc_version().unwrap();
+ let target = ::rustc_host();
let p = project("foo")
.file("Cargo.toml", r#"
});
test!(unused_overrides {
- let (_, target) = ::cargo::ops::rustc_version().unwrap();
+ let target = ::rustc_host();
let p = project("foo")
.file("Cargo.toml", r#"
});
test!(propagation_of_l_flags {
- let (_, target) = ::cargo::ops::rustc_version().unwrap();
+ let target = ::rustc_host();
let p = project("foo")
.file("Cargo.toml", r#"
[project]
});
test!(propagation_of_l_flags_new {
- let (_, target) = ::cargo::ops::rustc_version().unwrap();
+ let target = ::rustc_host();
let p = project("foo")
.file("Cargo.toml", r#"
[project]
});
test!(build_deps_not_for_normal {
- let (_, target) = ::cargo::ops::rustc_version().unwrap();
+ let target = ::rustc_host();
let p = project("foo")
.file("Cargo.toml", r#"
[project]
});
test!(cfg_override {
- let (_, target) = ::cargo::ops::rustc_version().unwrap();
+ let target = ::rustc_host();
let p = project("foo")
.file("Cargo.toml", r#"
// See #1515
test!(native_plugin_dependency_with_custom_ar_linker {
- let (_, target) = ::cargo::ops::rustc_version().unwrap();
+ let target = ::rustc_host();
let foo = project("foo")
.file("Cargo.toml", r#"
use support::{RUNNING, COMPILING, DOCTEST};
use hamcrest::{assert_that, existing_file};
use cargo::util::process;
-use cargo::ops::rustc_version;
fn setup() {
}
if disabled() { return }
let target = alternate();
- let (_, host) = rustc_version().unwrap();
+ let host = ::rustc_host();
let p = project("foo")
.file("Cargo.toml", r#"
[package]
mod test_cargo_test;
mod test_cargo_version;
mod test_shell;
+
+fn rustc_host() -> String {
+ cargo::ops::rustc_version("rustc").unwrap().1
+}